# $ find .  | grep "R$" | xargs grep -n "subset" --color=auto
# seurat-object-4.0.4/R/seurat.R:2497:subset.Seurat <- function(
# seurat-object-4.0.4/R/assay.R:858:subset.Assay <- function(x, cells = NULL, features = NULL, ...) {

# 这是一个S3类，有针对 Assay 和 Seurat 类的函数实现。




#' @describeIn Seurat-methods Subset a \code{\link{Seurat}} object
#'
#' @inheritParams CellsByIdentities
#' @param subset Logical expression indicating features/variables to keep
#' @param idents A vector of identity classes to keep
#'
#' @return \code{subset}: A subsetted \code{Seurat} object
#'
#' @importFrom rlang enquo
#
#' @aliases subset
#' @seealso \code{\link[base]{subset}} \code{\link{WhichCells}}
#'
#' @export
#' @method subset Seurat
#'
#' @examples
#' # `subset' examples
#' subset(pbmc_small, subset = MS4A1 > 4)
#' subset(pbmc_small, subset = `DLGAP1-AS1` > 2)
#' subset(pbmc_small, idents = '0', invert = TRUE)
#' subset(pbmc_small, subset = MS4A1 > 3, slot = 'counts')
#' subset(pbmc_small, features = VariableFeatures(object = pbmc_small))
#'
subset.Seurat <- function(
  x,
  subset,
  cells = NULL, #细胞
  features = NULL, #基因
  idents = NULL, # 分类
  return.null = FALSE, 
  ...
) {
  x <- UpdateSlots(object = x) #更新对象

  if (!missing(x = subset)) { #如果提供了 subset，则先把它变为表达式
    subset <- enquo(arg = subset) # 这个传递了表达式，而且没有加引号！！enquo() 这个函数怎么用？ //todo
  }


  cells <- WhichCells( # 后面说 WhichCells()函数
    object = x,
    cells = cells, #按cells参数
    idents = idents, #按 类别
    expression = subset, #按表达式
    return.null = TRUE,
    ...
  )

  # 如果没有细胞返回
  if (length(x = cells) == 0) {
    # 如果允许返回 NULL，则返回NULL，否则报错。
    if (isTRUE(x = return.null)) {
      return(NULL)
    }
    stop("No cells found", call. = FALSE)
  }

  # 所有的细胞都在sce对象中，且长度相等，且没有指定 features，则返回原始 Seurat 对象
  if (all(cells %in% Cells(x = x)) && # 后续说 Cells(sce) 函数
    length(x = cells) == length(x = Cells(x = x)) && 
    is.null(x = features)) {
    return(x)
  }

  # 如果不是所有的都在 cells中，则清空2个slot: graphs, neighbors
  if (!all(colnames(x = x) %in% cells)) {
    slot(object = x, name = 'graphs') <- list()
    slot(object = x, name = 'neighbors') <- list()
  }

  # 过滤Seurat对象，返回 Assay类 的实例名字，返回的是字符串
  assays <- FilterObjects(object = x, classes.keep = 'Assay')
  #> Key(pbmc_small)
  #  RNA     pca    tsne 
  # "rna_"   "PC_" "tSNE_" 
  #> FilterObjects(object = pbmc_small, classes.keep = 'Assay')
  #[1] "RNA"

  # Filter Assay objects
  for (assay in assays) {

    # 如果没有指定 features 就使用全部 features
    assay.features <- features %||% rownames(x = x[[assay]])

    # 对该 assay 重新赋值
    slot(object = x, name = 'assays')[[assay]] <- tryCatch(
      # because subset is also an argument, we need to explictly use the base::subset function
      # 同名的函数和参数名字，在函数内部默认使用参数。想使用函数，需要加R包前缀

      # 对于 assay 子对象，使用 subset.Assay 函数获取df矩阵的行和列，该函数下文说。
      expr = base::subset(x = x[[assay]], cells = cells, features = assay.features),

      # 获取error对象中的消息内容: e$message
      error = function(e) {
        if (e$message == "Cannot find features provided") {
          return(NULL)
        } else {
          stop(e)
        }
      }
    )
  }


  # 对于 pbmc_small@assays 这个list，过滤掉空的元素
  slot(object = x, name = 'assays') <- Filter(
    f = Negate(f = is.null), # Negate 高阶函数，相当于原函数结果加not。
    x = slot(object = x, name = 'assays')
  )

  # 过滤后，不能没有默认assay！
  # 如果 Assay 子类的对象个数为0，或者默认assay为空，则报错
  if (length(x = FilterObjects(object = x, classes.keep = 'Assay')) == 0 || 
    is.null(x = x[[DefaultAssay(object = x)]]) ) {
    stop("Under current subsetting parameters, the default assay will be removed. Please adjust subsetting parameters or change default assay.", call. = FALSE)
  }



  # Filter DimReduc objects | 过滤降维元素
  for (dimreduc in FilterObjects(object = x, classes.keep = 'DimReduc')) {
    x[[dimreduc]] <- tryCatch(
      # 下文讲泛型函数 subset.DimReduc()
      expr = subset.DimReduc(x = x[[dimreduc]], cells = cells, features = features),
      error = function(e) {
        if (e$message %in% c("Cannot find cell provided", "Cannot find features provided")) {
          return(NULL)
        } else {
          stop(e)
        }
      }
    )
  }


  # Remove metadata for cells not present
  # 按 cells 保留 meta.data 
  slot(object = x, name = 'meta.data') <- slot(object = x, name = 'meta.data')[cells, , drop = FALSE]
  

  # Recalculate nCount and nFeature
  # 重新计算 nCount 和 nFeature
  for (assay in FilterObjects(object = x, classes.keep = 'Assay')) {
    n.calc <- CalcN(object = x[[assay]])
    if (!is.null(x = n.calc)) { #如果返回值非空，则加上 _ 和 assay 名后缀
      names(x = n.calc) <- paste(names(x = n.calc), assay, sep = '_')
      x[[names(x = n.calc)]] <- n.calc # "[[.Seurat" 函数
    }
  }

  # 对 Seurat对象的@active.ident 按cells取子集
  # 左侧: "Idents<-" 下文讲
  # 右侧: 返回的是 slot(object = object, name = 'active.ident')，不在 meta.data 中。
  # > head( slot(object = pbmc_small, name = 'active.ident') )
  #ATGCCAGAACGACT CATGGCCTGTGCAT GAACCTGATGAACC TGACTGGATTCTCA AGTCAGACTGCACA 
  #             0              0              0              0              0 
  #TCTGATACACGTGT 
  #             0 
  #Levels: 0 1 2
  Idents(object = x, drop = TRUE) <- Idents(object = x)[cells]


  # subset images | 对图像对象取子集  (先跳过)
  for (image in Images(object = x)) {
    x[[image]] <- base::subset(x = x[[image]], cells = cells)
  }

  return(x)
}












###########
# subset.Assay 
#$ find . | grep "R$" | xargs grep -n "subset.Assay" --color=auto
#./seurat-object-4.0.4/R/assay.R:858:subset.Assay <- function(x, cells = NULL, features = NULL, ...) {


#' @describeIn Assay-methods Subset an \code{Assay}
#'
#' @return \code{subset}: A subsetted \code{Assay}
#'
#' @importFrom stats na.omit
#'
#' @export
#' @method subset Assay
#'
subset.Assay <- function(x, cells = NULL, features = NULL, ...) {
  CheckDots(...) #检查...参数

  #(A1) 如果没有指定cells参数，则使用全部细胞
  cells <- cells %||% colnames(x = x) 
  # 如果cells全是na，则使用全部细胞
  if (all(is.na(x = cells))) {
    cells <- colnames(x = x)
  # 如果cells部分是na，则警告，并过滤掉na
  } else if (any(is.na(x = cells))) {
    warning("NAs passed in cells vector, removing NAs")
    cells <- na.omit(object = cells)
  }

  #(A2) 如果不指定基因，默认使用全部基因。
  features <- features %||% rownames(x = x)
  # 全部是NA，则使用全部基因。部分是na则警告。
  if (all(is.na(x = features))) {
    features <- rownames(x = x)
  } else if (any(is.na(x = features))) {
    warning("NAs passed in the features vector, removing NAs")
    features <- na.omit(object = features)
  }

  #(A3) 如果行列和x相同，直接返回x
  if (all(  sapply(X = list(features, cells), FUN = length) == dim(x = x)  )) {
    return(x)
  }

  #(A4) 如果feature是数字，则按照行名取
  if (is.numeric(x = features)) {
    features <- rownames(x = x)[features]
  }

  #(A5) 全部替换掉，Key前缀，如 rna_CD4 替换后为 CD4
  features <- gsub(
    pattern = paste0('^', Key(object = x)),
    replacement = '',
    x = features
  )

  #(A6) 取交集:输入的gene，行名
  features <- intersect(x = features, y = rownames(x = x))

  #(A7) 如果交集长度为0，报错
  if (length(x = features) == 0) {
    stop("Cannot find features provided")
  }

  #(A8) x本身就是一个assay，比如 x=sce@assays$RNA, 如果 x@counts 的列数 等于 x的列数
  # //这个 if 什么意思？ //todo
  if (ncol(x = GetAssayData(object = x, slot = 'counts')) == ncol(x = x)) {
    # 重新赋值，给x@counts的子集，按 基因、细胞id
    slot(object = x, name = "counts") <- GetAssayData(object = x, slot = "counts")[features, cells, drop = FALSE]
  }

  # 按 基因、细胞id取 x@data 的子集
  slot(object = x, name = "data") <- GetAssayData(object = x, slot = "data")[features, cells, drop = FALSE]

  # (B1)取 scale.data 的列名: cell id
  cells.scaled <- colnames(x = GetAssayData(object = x, slot = "scale.data"))
  # 只保留 在 cells 参数中的部分
  cells.scaled <- cells.scaled[cells.scaled %in% cells]
  # 取小集合在大集合的子集，并保持在大集合中的位置顺序。
  # 独特点：用大集合，去匹配小集合中的元素位置，出现大量na。然后取小集合元素，结果就保证了元素顺序和大集合一致。
  cells.scaled <- cells.scaled[na.omit(object = match(x = colnames(x = x), table = cells.scaled))]

  # (B2)取 scale.data 的行名: symbol
  features.scaled <- rownames(x = GetAssayData(object = x, slot = 'scale.data'))
  # 只保留在参数 features 出现的部分
  features.scaled <- features.scaled[features.scaled %in% features]
  # 如果 cell和symbol都不是0，则取 x@scale.data的子集，否则返回空矩阵。
  slot(object = x, name = "scale.data") <- if (length(x = cells.scaled) > 0 && length(x = features.scaled) > 0) {
    GetAssayData(object = x, slot = "scale.data")[features.scaled, cells.scaled, drop = FALSE]
  } else {
    new(Class = 'matrix')
  }

  # 高变基因，取子集。这个定义在 assay的一个slot=var.features，是一个字符串。
  VariableFeatures(object = x) <- VariableFeatures(object = x)[VariableFeatures(object = x) %in% features]
  
  # 对基因的meta.data 按行取子集，保持df结构
  #> head(pbmc_small@assays$RNA@meta.features, n=2)
  #      vst.mean vst.variance vst.variance.expected vst.variance.standardized vst.variable
  #MS4A1   0.3875     1.025158              1.141162                 0.8983463        FALSE
  #CD79B   0.6000     1.281013              2.707623                 0.4731134        FALSE
  slot(object = x, name = 'meta.features') <- x[[]][features, , drop = FALSE]
  
  #返回该 Assay 对象
  return(x)
}










###########
# subset.DimReduc()
# ./seurat-object-4.0.4/R/dimreduc.R:685:subset.DimReduc <- function(x, cells = NULL, features = NULL, ...) {


#' @describeIn DimReduc-methods Subset a \code{DimReduc} object
#'
#' @param cells,features Cells and features to keep during the subset
#'
#' @return \code{subset}: \code{x} for cells \code{cells} and features
#' \code{features}
#'
#' @export
#' @method subset DimReduc
#'
subset.DimReduc <- function(x, cells = NULL, features = NULL, ...) {
  CheckDots(...) #检查参数...

  #(A1) %iff% 尽可能取null，如果第一个为null，则返回null；如果第一个不是null则取第二个值。
  # 如果 Cells(x = x) 不为空，则取后面的
  cells <- Cells(x = x) %iff% cells %||% Cells(x = x)
  
  #(A2) 如果 cells 全na，则取全部细胞。如果部分为na，则去掉na。
  if (all(is.na(x = cells))) {
    cells <- Cells(x = x)
  } else if (any(is.na(x = cells))) {
    warning("NAs passed in cells vector, removing NAs")
    cells <- na.omit(object = cells)
  }

  #(A3) 如果 Loadings 行名为空，则features取空；否则使用参数
  # features <- rownames(x = x) %iff% features %||% rownames(x = x)
  features <- rownames(x = Loadings(object = x)) %iff% features %||% rownames(x = Loadings(object = x))
  
  # 如果行列不变，则返回x。
  if (all(sapply(X = list(features, cells), FUN = length) == dim(x = x))) {
    return(x)
  }

  #(A4) 降维对象的 cell.embeddings 细胞位置，如果细胞为空，则为空矩阵。
  slot(object = x, name = 'cell.embeddings') <- if (is.null(x = cells)) {
    new(Class = 'matrix')
  } else {
    # 如果有细胞，
    #数字的转为细胞id
    if (is.numeric(x = cells)) {
      cells <- Cells(x = x)[cells]
    }
    # 求交集: 传入的细胞，降维对象的细胞
    cells <- intersect(x = cells, y = Cells(x = x))
    # 如果细胞长度为0，报错
    if (length(x = cells) == 0) {
      stop("Cannot find cell provided", call. = FALSE)
    }
    # 按细胞取子集，保持df结构。
    # 按行取不会损失df结构吧，我认为这个drop参数可以省略。// todo
    x[[cells, , drop = FALSE]]
  }


  # (A5) 降维对象的 feature.loadings
  # 如果 features 为空，则为空矩阵
  slot(object = x, name = 'feature.loadings') <- if (is.null(x = features)) {
    new(Class = 'matrix')
  } else {
    # 否则
    # 序号转为 symbol
    if (is.numeric(x = features)) {
      features <- rownames(x = x)[features]
    }

    #求交集
    features.loadings <- intersect(
      x = rownames(x = Loadings(object = x, projected = FALSE)),
      y = features
    )
    # 如果交集为空，则报错
    if (length(x = features.loadings) == 0) {
      stop("Cannot find features provided", call. = FALSE)
    }
    # 按行返回子集
    Loadings(object = x, projected = FALSE)[features.loadings, , drop = FALSE]
  }


  # (A6) assay@feature.loadings.projected 这个slot干啥的？
  slot(object = x, name = 'feature.loadings.projected') <- if (is.null(x = features) || !Projected(object = x)) {
    new(Class = 'matrix')
  } else {
    features.projected <- intersect(
      x = rownames(x = Loadings(object = x, projected = TRUE)),
      y = features
    )
    if (length(x = features.projected) == 0) {
      stop("Cannot find features provided", call. = FALSE)
    }
    Loadings(object = x, projected = TRUE)[features.projected, , drop = FALSE]
  }

  # (A7) PC的显著性，赋值空对象
  slot(object = x, name = 'jackstraw') <- new(Class = 'JackStrawData')

  return(x)
}














###########
# $ find .  | grep "R$" | xargs grep -n "WhichCells" --color=auto
# seurat-object-4.0.4/R/generics.R:870:WhichCells <- function(object, ...) {

#' Identify cells matching certain criteria
#'
#' Returns a list of cells that match a particular set of criteria such as
#' identity class, high/low values for particular PCs, etc.
#'
#' @param object An object
#' @param ... Arguments passed to other methods
#'
#' @return A vector of cell names
#'
#' @rdname WhichCells
#' @export WhichCells
#'
#' @concept data-access
#'
#' @seealso \code{\link{FetchData}}
#'
#' @examples
#' WhichCells(pbmc_small, idents = 2)
#' WhichCells(pbmc_small, expression = MS4A1 > 3)
#' levels(pbmc_small)
#' WhichCells(pbmc_small, idents = c(1, 2), invert = TRUE)
#'
WhichCells <- function(object, ...) {
  UseMethod(generic = 'WhichCells', object = object)
}

# seurat-object-4.0.4/R/seurat.R:1860:WhichCells.Seurat <- function(

#' @param idents A vector of identity classes to keep
#' @param slot Slot to pull feature data for
#' @param downsample Maximum number of cells per identity class, default is
#' \code{Inf}; downsampling will happen after all other operations, including
#' inverting the cell selection
#' @param seed Random seed for downsampling. If NULL, does not set a seed
#' @inheritDotParams CellsByIdentities
#'
#' @importFrom stats na.omit
#' @importFrom rlang is_quosure enquo eval_tidy
#'
#' @rdname WhichCells
#' @export
#' @method WhichCells Seurat
#'
WhichCells.Seurat <- function(
  object,
  cells = NULL,
  idents = NULL,
  expression,
  slot = 'data',
  invert = FALSE,
  downsample = Inf,
  seed = 1,
  ...
) {
  CheckDots(..., fxns = CellsByIdentities) # 检查参数 ... //todo 看不懂，继续跳过去

  # 如果传入的有随机数种子
  if (!is.null(x = seed)) {
    set.seed(seed = seed)
  }

  # 更新对象
  object <- UpdateSlots(object = object)

  #(A1) 细胞，如果空，则默认全集
  cells <- cells %||% colnames(x = object)
  # 如果是编号，转为cell id
  if (is.numeric(x = cells)) {
    cells <- colnames(x = object)[cells]
  }
  # 细胞顺序: 传入的顺序
  cell.order <- cells


  #(A2) 如果 idents 非空
  if (!is.null(x = idents)) {
    # 如果有某个idents不在 levels 中，报错：
    if (any(!idents %in% levels(x = Idents(object = object)))) {
      stop(
        "Cannot find the following identities in the object: ",
        paste(
          idents[!idents %in% levels(x = Idents(object = object))],
          sep = ', ' #这里应该为 collapse=", " 
          # 已经提PR: https://github.com/mojaveazure/seurat-object/pull/40 
        )
      )
    }

    # 对参数 idents 循环，这里 lapply 代替for循环了。
    cells.idents <- unlist(x = lapply(
      X = idents,
      FUN = function(i) {
        # 取出等于某个ident的，返回的是 T or F 的list
        cells.use <- which(x = as.vector(x = Idents(object = object)) == i)
        # 返回cell id
        cells.use <- names(x = Idents(object = object)[cells.use])
        return(cells.use)
      }
    )) #解开list unlist
    
    # 求交集：输入的 cells，输入的 idents 对应的 cell id
    cells <- intersect(x = cells, y = cells.idents)
  }



  # (A3) 如果表达式非空
  if (!missing(x = expression)) {
    # (B1) 获取 这几个类的名字
    objects.use <- FilterObjects(
      object = object,
      classes.keep = c('Assay', 'DimReduc', 'SpatialImage')
    )

    # (B2) 获取 这几个类的对象总的 Key
    object.keys <- sapply(
      X = objects.use,
      FUN = function(i) {
        return(Key(object = object[[i]]))
      }
    )

    # (B3) 把这些 key 使用 | 连起来
    key.pattern <- paste0('^', object.keys, collapse = '|')

    # (B4) 获取表达式，接下来看不懂了 //todo
    # 把整个try语句放到一个if中
    expr <- if (tryCatch(expr = is_quosure(x = expression), error = function(...) FALSE)) {
      expression
    } else if (is.call(x = enquo(arg = expression))) {
      enquo(arg = expression)
    } else {
      parse(text = expression)
    }

    # (B5) 把表达式变成字符串
    expr.char <- suppressWarnings(expr = as.character(x = expr))
    
    # (B6) 把字符串使用' ' 分隔开
    expr.char <- unlist(x = lapply(X = expr.char, FUN = strsplit, split = ' '))

    # (B7) 对每个单词替换
    # '(' to ''
    expr.char <- gsub(
      pattern = '(',
      replacement = '',
      x = expr.char,
      fixed = TRUE
    )

    # '`' to ''
    expr.char <- gsub(
      pattern = '`',
      replacement = '',
      x = expr.char
    )
    
    # (B8) 看哪些单词，在对象的行名(gene symbol)、meta.data的列名、或者和Key关键词匹配
    # 这一步写的十分精彩！ This step Very good! Marvelous lines! 
    vars.use <- which(
      x = expr.char %in% rownames(x = object) |
        expr.char %in% colnames(x = object[[]]) |
        grepl(pattern = key.pattern, x = expr.char, perl = TRUE)
    )

    # (B9) 使用这些相关单词，取这些列的数据，每一行为一个cell
    data.subset <- FetchData(
      object = object,
      vars = unique(x = expr.char[vars.use]),
      cells = cells,
      slot = slot
    )

    # (B10) 按 expr 对 data 进行过滤，应该给出的一系列布尔值；然后获取行名
    cells <- rownames(x = data.subset)[eval_tidy(expr = expr, data = data.subset)]
  }



  # (A4) 如果设置反向选取
  if (isTRUE(x = invert)) {
    # 全部细胞
    cell.order <- colnames(x = object)
    # 获取不在上面的 cells 中的细胞
    cells <- colnames(x = object)[!colnames(x = object) %in% cells]
  }


  # (A5) 返回一个list，name为 cluster，value为cell id
  cells <- CellsByIdentities(object = object, cells = cells, ...)

  # (A6) 对于每个cluster中的cell
  cells <- lapply(
    X = cells,
    FUN = function(x) {
      # 如果细胞数超过规定值，就非重复的抽样
      if (length(x = x) > downsample) {
        x <- sample(x = x, size = downsample, replace = FALSE)
      }
      # 否则啥也不干，返回细胞id
      return(x)
    }
  )

  # (A7) 展开list，丢掉cluster名字；过滤掉na，转为字符串
  cells <- as.character(x = na.omit(object = unlist(x = cells, use.names = FALSE)))
  
  # (A8) 排序: 大集合在小集合中的下标，去掉na，然后是小集合的元素，按照大集合的顺序输出
  cells <- cells[na.omit(object = match(x = cell.order, table = cells))]
  
  # 返回 cell id
  return(cells)
}


该函数的几个问题：
1. cell.order 出现3次，每次是否都必要? 
第一次是指定的cell，或者默认的所有cell 作为全集。
第二次是如果要补集，则使用全部细胞作为 全集。
最后一次是必要的，保证按照全集的顺序输出。

2. 关于表达式的处理，不是很懂。






# seurat-object-4.0.4/R/assay.R:639:WhichCells.Assay <- function(


#' @param cells Subset of cell names
#' @param expression A predicate expression for feature/variable expression,
#' can evaluate anything that can be pulled by \code{FetchData}; please note,
#' you may need to wrap feature names in backticks (\code{``}) if dashes
#' between numbers are present in the feature name
#' @param invert Invert the selection of cells
#'
#' @importFrom stats na.omit
#' @importFrom rlang is_quosure enquo eval_tidy
#'
#' @rdname WhichCells
#' @export
#' @method WhichCells Assay
#'
WhichCells.Assay <- function(
  object,
  cells = NULL,
  expression,
  invert = FALSE,
  ...
) {

  CheckDots(...) #检查参数 ...

  #(A1) 如果cells为空，则设为全部细胞
  cells <- cells %||% colnames(x = object)

  #(A2) 如果有表达式，且变为表达式后非空 //todo substitute
  if (!missing(x = expression) && !is.null(x = substitute(expr = expression))) {
    # 拼凑表达式 ^rna_
    key.pattern <- paste0('^', Key(object = object))

    # 获取表达式 // todo
    expr <- if (tryCatch(expr = is_quosure(x = expression), error = function(...) FALSE)) {
      expression
    } else if (is.call(x = enquo(arg = expression))) {
      enquo(arg = expression)
    } else {
      parse(text = expression)
    }

    # 抑制警告，表达式变字符串
    expr.char <- suppressWarnings(expr = as.character(x = expr))
    # 字符串使用' '分割开，展开list
    expr.char <- unlist(x = lapply(X = expr.char, FUN = strsplit, split = ' '))
    # 去掉每个单词的 ^rna_ 前缀
    expr.char <- gsub(
      pattern = key.pattern,
      replacement = '',
      x = expr.char,
      perl = TRUE
    )
    # 去掉每个单词的(
    expr.char <- gsub(
      pattern = '(',
      replacement = '',
      x = expr.char,
      fixed = TRUE
    )
    # 去掉每个单词的'`'
    expr.char <- gsub(
      pattern = '`',
      replacement = '',
      x = expr.char
    )

    # 保留 单词在 assay对象 行名(symbol)中的部分
    vars.use <- which(x = expr.char %in% rownames(x = object))
    expr.char <- expr.char[vars.use]

    # 取这些基因的表达df，转置，在转为df
    data.subset <- as.data.frame(x = t(x = as.matrix(x = object[expr.char, ])))

    # 列名为 symbol
    colnames(x = data.subset) <- expr.char

    # 按照 expr 对 data 过滤，返回符合条件的行名(symbol)
    cells <- rownames(x = data.subset)[eval_tidy(expr = expr, data = data.subset)]
  }


  #(A3) 如果定义过取反
  if (invert) {
    # 取不在上述结果的 cell id
    cells <- colnames(x = object)[!colnames(x = object) %in% cells]
  }

  #(A4) 展开cells，不要name，去掉na
  cells <- na.omit(object = unlist(x = cells, use.names = FALSE))
  # 返回字符串
  return(as.character(x = cells))
}














############## CellsByIdentities()

测试: 返回的是一个list，name为 cluster，值为cell id;

> lapply(CellsByIdentities(pbmc_small), function(x){head(x, n=3)})
$`0`
[1] "ATGCCAGAACGACT" "CATGGCCTGTGCAT" "GAACCTGATGAACC"

$`1`
[1] "TTACCATGAATCGC" "ATAGGAGAAACAGA" "GCGCACGACTTTAC"

$`2`
[1] "AGGTCATGAGTGTC" "AGAGATGATCTCGC" "GGGTAACTCTAGTG"





# ./seurat-object-4.0.4/R/seurat.R:205:CellsByIdentities <- function(

#' Get cell names grouped by identity class
#'
#' @param object A Seurat object
#' @param idents A vector of identity class levels to limit resulting list to;
#' defaults to all identity class levels
#' @param cells A vector of cells to grouping to
#' @param return.null If no cells are request, return a \code{NULL};
#' by default, throws an error
#'
#' @return A named list where names are identity classes and values are vectors
#' of cells belonging to that class
#'
#' @export
#'
#' @concept data-access
#'
#' @examples
#' CellsByIdentities(object = pbmc_small)
#'
CellsByIdentities <- function(
  object,
  idents = NULL,
  cells = NULL,
  return.null = FALSE
) {
  # (A1) cells 参数
  cells <- cells %||% colnames(x = object) # 细胞不设置，则使用全部细胞

  cells <- intersect(x = cells, y = colnames(x = object)) #和全部细胞求交集

  # 如果长度为0，则返回NULL，或者报错。
  if (length(x = cells) == 0) {
    if (isTRUE(x = return.null)) {
      return(NULL)
    }
    stop("Cannot find cells provided")
  }

  # (A2) idents 参数
  # idents 如果为空，则使用全部levels
  idents <- idents %||% levels(x = object)
  # 求和所有levels的交集
  idents <- intersect(x = idents, y = levels(x = object))
  # 如果idents 长度为0，报错
  if (length(x = idents) == 0) {
    stop("None of the provided identity class levels were found", call. = FALSE)
  }

  # (A3) 核心语句
  # 对 idents 进行循环，循环变量 i，
  #   在idents中按cells取子集，取等于i的cells子集
  #    返回不精简，就是返回list；使用的name就是循环变量 idents 的i
  cells.idents <- sapply(
    X = idents,
    FUN = function(i) {
      return(cells[as.vector(x = Idents(object = object)[cells]) == i])
    },
    simplify = FALSE,
    USE.NAMES = TRUE
  )

  # (A4) 如果有cells取子集后是na，则新增NA键，记录NA的细胞?? //todo
  # cells.idents 在上文是一个list，这里为什么使用 ["NA"]而不是[[]]?
  # 什么情况下会有NA呢？
  if (any(is.na(x = Idents(object = object)[cells]))) {
    cells.idents["NA"] <- names(x = which(x = is.na(x = Idents(object = object)[cells])))
  }

  return(cells.idents)
}











######## VariableFeatures() S3 方法。
VariableFeatures()

> showMethods( VariableFeatures )
Function "VariableFeatures":
 <not an S4 generic function>

> VariableFeatures
function (object, selection.method = NULL, ...) 
{
    UseMethod(generic = "VariableFeatures", object = object)
}
<bytecode: 0x000000001ee58f88>
<environment: namespace:SeuratObject>
这是一个S3类。



# seurat-object-4.0.4/R/seurat.R:1819:VariableFeatures.Seurat <- function(

#' @rdname VariableFeatures
#' @export
#' @method VariableFeatures Seurat
#'
#' @order 7
#'
VariableFeatures.Seurat <- function(
  object,
  selection.method = NULL,
  assay = NULL,
  ...
) {
  CheckDots(...)
  object <- UpdateSlots(object = object)
  assay <- assay %||% DefaultAssay(object = object)
  return(VariableFeatures(object = object[[assay]], selection.method = selection.method))
}


#/seurat-object-4.0.4/R/assay.R:574:VariableFeatures.Assay <- function(object, selection.method = NULL, ...) {

#' @rdname VariableFeatures
#' @export
#' @method VariableFeatures Assay
#'
VariableFeatures.Assay <- function(object, selection.method = NULL, ...) {
  CheckDots(...)
  if (!is.null(x = selection.method)) {
    vf <- HVFInfo(
      object = object,
      selection.method = selection.method,
      status = TRUE
    )
    return(rownames(x = vf)[which(x = vf[, "variable"][, 1])])
  }

  return(slot(object = object, name = 'var.features'))
}

原来在 Assay 类中。
> slotNames(pbmc_small@assays$RNA)
[1] "counts"        "data"          "scale.data"    "key"          
[5] "assay.orig"    "var.features"  "meta.features" "misc"













#' @describeIn Seurat-methods Number of cells and features for the active assay
#'
#' @return \code{dim}: The number of features (\code{nrow}) and cells
#' (\code{ncol}) for the default assay; \strong{note}: while the number of
#' features changes depending on the active assay, the number of cells remains
#' the same across all assays
#'
#' @export
#' @method dim Seurat
#'
#' @examples
#' # Get the number of features in an object
#' nrow(pbmc_small)
#'
#' # Get the number of cells in an object
#' ncol(pbmc_small)
#'
dim.Seurat <- function(x) {
  x <- UpdateSlots(object = x)
  return(dim(x = x[[DefaultAssay(object = x)]]))
}

实质就是默认assay的dim，实现一个方法，相当于实现了3个: nrow, ncol, dim










######## Cells(sce) 函数
# /seurat-object-4.0.4/R/generics.R:109:Cells <- function(x) {

#' Get cells present in an object
#'
#' @param x An object
#'
#' @return A vector of cell names
#'
#' @rdname Cells
#' @export Cells
#'
#' @concept data-access
#'
#' @examples
#' Cells(x = pbmc_small)
#'
Cells <- function(x) {
  UseMethod(generic = 'Cells', object = x)
}


# /seurat-object-4.0.4/R/default.R:12:Cells.default <- function(x) {

#' @rdname Cells
#' @export
#'
Cells.default <- function(x) {
  return(colnames(x = x))
}

原来就是行名，根据上文 dimnames 的定义，就是 默认assay的行名。







#3.9 提了一个PR


